#include "AugmenterComp.h"

#include "Joueur.h"

#include "Qlib.h"

#include <QtGui/QGridLayout>
#include <QtGui/QGroupBox>
#include <QtGui/QLabel>
#include <QtGui/QSpinBox>
#include <QtGui/QPushButton>
#include <QtGui/QLCDNumber>

#include <QtGui/QApplication>

using namespace std;

/** Constructeur par défaut.
 * On prépare les différentes structures de données (groupe des
 * widgets), boutons "OK" et "Annuler". Le gros du travail est
 * effectué par prepareAffichage.
 *
 * @param j pointeur sur le Joueur à modifier.
 * @param parent pointeur sur le widget parent (orphelin par défaut).
 */
AugmenterComp::AugmenterComp(Joueur* j, QWidget *parent)
  : BaseUI( QString::fromUtf8("AugmenterComp"), parent ), nbrPP( 0 )
{
  joueur = j;

  groupe = new QGroupBox( trUtf8("Compétences actuelles"), this );
  groupeLayout  = new QGridLayout( groupe );

  PP = new QLCDNumber( this );
  PP -> setSegmentStyle(QLCDNumber::Flat);

  prepareAffichage();

  prepareBoutons();

  fenetreLayout -> addWidget( PP );

  fenetreLayout -> addWidget( groupe );

  setFenetreLayout();
}

/**
 * Constructeur de copie. Il faut faire attention à bien copier le
 * pointeur sur le personnage (Joueur) à modifier.
 *
 * @param augComp instance de AugmenterComp à dupliquer.
 */
AugmenterComp::AugmenterComp(const AugmenterComp& augComp)
  : BaseUI( augComp ), nbrPP( augComp.nbrPP )
{
  joueur = augComp.joueur;

  groupe = new QGroupBox( trUtf8("Compétences actuelles"), this );
  groupeLayout  = new QGridLayout( groupe );

  PP = new QLCDNumber( this );
  PP -> setSegmentStyle(QLCDNumber::Flat);

  prepareAffichage();

  prepareBoutons();

  fenetreLayout -> addWidget( PP );

  fenetreLayout -> addWidget( groupe );

  setFenetreLayout(); 
}


/**
 * Destructeur, ne fait rien de spécial.
 */
AugmenterComp::~AugmenterComp()
{}

/** Méthode qui affiche le widget.
 * On se repose sur les fonctionnalités des widgets utilisés, et sur
 * le connecteur valeurChange().
 *
 * @return StatusCode \e true si choix accepté, \e false sinon. Le
 * nombre de PP restants est contenu dans valeur().
 */
StatusCode AugmenterComp::choixFait()
{
  this -> show();

  qApp -> exec();

  return StatusCode( OK, PP -> value() );
}

/** Crée l'ensemble des widgets permettant l'évolution des compétences.
 * Dans un premier temps, on récupère le nombre de compétences que le
 * PJ possède déjà et un pointeur sur le conteneur.
 *
 * Ensuite on crée une légende et un spinbox pour chacune de ces
 * compétences. La valeur minimale de chaque spinbox est la valeur
 * actuelle de la compétence, la valeur maximale et 20 (Rappelons
 * qu'un 1 représente toujours un échec). Les difflrents spinbox sont
 * connectés au slot valeurChange().
 *
 * Finalement on affiche le nombre de PP actuel.
 *
 * Le niveau de sortie est paramétré par BaseUI::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.\n
 * - \e DEBUG affiche pour chaque compétence son index dans la liste des
 * compétences et son nom.
 */
void AugmenterComp::prepareAffichage()
{
  /*Debug::*/empileNiveau( &interne );
  func() << "AugmenterComp::prepareAffichage -> début" << endmsg;

  aDeja = joueur -> diverses( aDejaCombien );

  unsigned int i;

  for (i = 0; i < aDejaCombien; i += 2)
    {
      nomComp.push_back( new QLabel( trUtf8((joueur -> compDsListe
					     (aDeja -> at(i) ) ). nom() .c_str() ),
				     this) );
      valComp.push_back( new QSpinBox( this ) );
      valComp.back() -> setMinimum( aDeja -> at(i + 1) );
      valComp.back() -> setMaximum( 20 );
      connect( valComp.back(), SIGNAL( valueChanged(int) ),
	       this, SLOT( valeurChange() ));
      debug() << i << " -> "<< toUtf8StdString( valComp.back() -> text() )
	      << endmsg;
    }

  nbrDeja = valComp.size();

  for (i = 0; i <  aDejaCombien; i += 2)
    {
      groupeLayout -> addWidget(nomComp[i / 2], (i / 2) % 10, (i / 20) * 2 );
      groupeLayout -> addWidget(valComp[i / 2], (i / 2) % 10, (i / 20) * 2 + 1);
    }

  groupe -> setLayout( groupeLayout );

  nbrPP = static_cast<int>(joueur -> nbrPP());

  PP -> display(nbrPP);

  func() << "AugmenterComp::prepareAffichage -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/** Crée les 2 boutons et les connecte à leur slot respectif.
 * Les deux boutons suivants sont créés : Quitter et OK. Le premier
 * provoque un arrêt du processus en cours, le second permet de
 * valider le choix effectué et de continuer.
 * 
 * Le niveau de sortie est paramétré par BaseUI::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.
 */
void AugmenterComp::prepareBoutons()
{
  /*Debug::*/empileNiveau( &interne );
  func() << "AugmenterComp::prepareBoutons -> début" << endmsg;

  boutons.push_back( new QPushButton( trUtf8("&Quitter"), this ) );
  boutons.back() -> setToolTip( trUtf8("Quitter le programme") );
  connect( boutons.back(), SIGNAL( clicked() ), this, SLOT( annuler() ) );
  boutons.push_back( new QPushButton( trUtf8("&OK"), this ) );
  boutons.back() -> setToolTip( trUtf8("Accepter et continuer") );
  connect( boutons.back() , SIGNAL( clicked() ), this, SLOT( fermer() ) );

  func() << "AugmenterComp::prepareBoutons -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/** Fonction appelée lors du changement de valeur d'un des spinbox.
 * Afin de déterminer le nombre de PP restants, on parcours bêtement
 * la liste des spinbox existants et on calcule de combien on a
 * augmenté chaque compétence (il est impossible d'en diminuer le
 * score), cara il n'est pas possible de savoir quel est le spinbox
 * activé.
 */
void AugmenterComp::valeurChange()
{
  int tmp(nbrPP);

  for(unsigned int i(0); i < nbrDeja; i++)
    tmp -= valComp[i] -> value() - aDeja -> at(2 * i + 1);

  PP -> display(tmp);
}

/** Fonction appelée lors de la validation du choix, ferme la fenêtre.

 * On doit ici redéfinir fermer(), pour s'assurer que l'on n'a pas
 * trop dépensé de PP et surtout appliquer les modifications aux
 * compétences du PJ.
 */
void AugmenterComp::fermer()
{
  OK = true;

  if ( PP -> value() < 0 )
    return;

  vector< unsigned int > tmp;

  tmp.assign( aDeja -> begin(), aDeja -> end() );

  for (unsigned int i(0); i < nbrDeja; i++)
    tmp[ 2 * i + 1 ] = valComp[i] -> value();
  
  joueur -> setDiverses( tmp );

  joueur -> setPP( PP -> value() );

  close();
}
